                             


                  Converting RMB Programs To The HP82335

    _____________________________________________________________________

    [1.0] OVERVIEW ...................................................  1

    [2.0] GETTING STARTED -- ADDRESSING & ASSIGN .....................  2

    [3.0] RMB OUTPUT STATEMENT .......................................  6

    [4.0] RMB ENTER STATEMENT ........................................ 11

    [5.0] ERROR, TIMEOUT, & SRQ HANDLING ............................. 14

    [6.0] OTHER I/O STATEMENTS ....................................... 16

    [7.0] A FEW QUICKBASIC EXAMPLES .................................. 17

    [APPENDIX] STRING HANDLING ....................................... 25

    _____________________________________________________________________

[%%]

                             Converting RMB Programs                          1


* [1.0] OVERVIEW: The HP 82335 HPIB Command Library has been around for
a long time and has proven popular with users of HP equipment.  Unfortunately,
most HP instrument manuals use example programs written in various dialects of
HP BASIC, particularly the so-called "Rocky Mountain BASIC" (RMB) variant, and
translating these example programs, even simple ones, to the 82335 code is not
always easy.  Translating complicated ones may be a major undertaking.

Under RMB, HPIB I/O capabilities are smoothly integrated with the language,
which offers features for error and timeout handling as well as other niceties.
The 82335 instead offers a library of HPIB I/O calls that are used as an
addition to languages that were never designed for I/O; as a result, while
82335 can do virtually any HPIB transaction that RMB can, it does so less
conveniently and in a more verbose fashion.

This document offers guidelines and examples for performing translations from
RMB to the 82335; the target language is QuickBASIC running programs
incorporating the 82335 calls for operation under DOS.  However, the discussion
is also relevant to other DOS or Windows languages, since the library's
functionality remains mostly the same from language to language -- though the
the 82335 Windows library calls have a different syntax from the DOS library
calls.  (See the Windows programming manual for the 82335 to understand the
syntax differences for the Windows library.)

Note that this document provides a general overview of porting considerations;
it does not cover all conceivable cases, since such a comprehensive document
would be hundreds of pages long.  However, it should be more than adequate for
the simple cases most commonly used in dealing with HP instruments.

Nor can this document begin to address the problems you will encounter in
converting RMB graphics, file-I/O, or other functions to QuickBASIC or some
other target DOS or Windows language; this discussion is necessarily restricted
to the subject of HPIB I/O.

* Note also that if you have example programs written in HP Series-80 BASIC
(for the HP-85, 86, or 87 computers) you will find that all the comments in
this document concerning conversions between HP BASIC I/O statements and the
82335 are just as valid as they are for RMB; the I/O functionality of the two
dialects of HP BASIC is almost identical.

However, if you have example programs written in HPL (an ancient HP desktop
calculator language) or for other vendors' HPIB cards, this document is
worthless, and unfortunately I don't know of another source that could fill
that need.

* Now that we are ready to proceed, there is one vital piece of information
you will need to understand the discussion in the rest of this document.

                             Converting RMB Programs                          2


RMB and QuickBASIC have different schemes for naming variables that can lead to
trouble.  RMB uses 16-bit integers, 64-bit reals, strings of characters, and
arrays of all those; QuickBASIC has a few more data types -- 16- and 32-bit
integers, 32- and 64-bit reals, strings of characters, and arrays of these
types.

This means that QuickBASIC supports all the data types that RMB does; the
problem arises in the convention used by QuickBASIC to define variable types;
it does so by using a suffix character:

   Int16var%         -- A QuickBASIC 16-bit integer variable.
   Int32var&         -- A QuickBASIC 32-bit integer variable.
   Real32var!        -- A QuickBASIC 32-bit real variable.
   Real64var#        -- A QuickBASIC 64-bit real variable.

Leave off a suffix and you end up with a 32-bit real; which means that if
you type the variable name:

   MyVar%

-- which is a 16-bit integer, and later type in:

   MyVar

-- by mistake, you have just entered an entirely different variable that is a
32-bit real.  That's the nastiest problem with this scheme, but in general the
use of suffixes to define data types leads to severe housekeeping problems and
is QuickBASIC's ugliest feature.  Anyway, keep in mind as you read this
document that the QuickBASIC suffixes are important and you need to keep them
straight.

[%%]


* [2.0] GETTING STARTED -- ADDRESSING & ASSIGN:  The first, essential
concern in writing an HPIB I/O program in any language is figuring out where a
particular device is on the HPIB.  Devices, such as instruments, printers, or
plotters, can have an HPIB address from 0 to 30; and to complicate matters,
there may in principle be multiple HPIB cards in controlling computer, so the
program has to be able to not only identify the address of a device -- but also
which HPIB card it is connected to.

In RMB, HPIB cards (or any I/O card for that matter) are identified by a unique
number, called an "interface select code" (or "select code", or simply ISC for
short), that usually corresponds to a DIP switch setting on the card -- though
in the case of I/O ports built into an RMB controller, the select codes are
normally "hardwired".  For example, on an RMB controller, the built-in HPIB
interface invariably has a select code of 7.

                             Converting RMB Programs                          3


So, in an RMB program, a device is identified by its HPIB address tacked on to
the end of the relevant HPIB card's select code; for example, you could output
a command string to a device at address 23 on HPIB port 7 with the RMB
statement:

   OUTPUT 723;"BEEP"

* The identical concern applies to the 82335; you have to identify the device
address and which card the device is attached to.  In fact, the 82335 also uses
select codes, and the default select code is also 7; but the resemblance is
misleading, since the 82335 select codes actually correspond to certain ranges
of addresses in the PC reserved memory space.  HP just liked using select codes
so much that when PCs came around they just adapted the idea to a different
environment.

This causes confusion in some cases, however, since HP sells a so-called
"Measurement Coprocessor" (MCP) card that contains the guts of an RMB computer
and plugs into a PC; it uses the PC as a host, but the programs run in the
MCP's own memory and on the MCP board's own microprocessor chip.  The MCP
board, since it has the hardware of an RMB controller,  also has its own HPIB
port, which is at select code 7; in some cases users who have both an MCP and
an 82335 become (understandably) confused and try to change the 82335 setting
from 7, fearing it would conflict with the MCP's HPIB port.  It often takes us
much effort to convince them that there is no hardware relationship between the
two select codes.

Anyway, to output the "BEEP" command with the 82335, you would use the 82335
IOOUTPUTS (output string) call as follows:

   Dev&=723
   Cmd$="BEEP"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

Note that the IOOUTPUTS call is more "verbose" than the RMB statement, though
you could reduce the number of calls with a few shortcuts.  For this (and some
other reasons we'll get to presently) a program written in RMB to perform HPIB
I/O tends to expand considerably when converted to QuickBASIC and the 82335.

                             Converting RMB Programs                          4


* Note that in the RMB example:

   OUTPUT 723;"BEEP"

-- the RMB OUTPUT statement uses the actual address of the instrument, 723, as
the destination for the "BEEP" string.  In practice it is an extremely bad idea
to do this, since if you have a lot of OUTPUT statements in a program and you
have to change the address in the program, you have to go through the entire
program and change every last one of them.  It is a lot smarter to store the
address in a variable and then use the variable to designate the destination:

   Dev=723
   OUTPUT Dev;"BEEP"

That way, if you change the address, you only have to change it in one place
in the entire program.

However, RMB takes this idea one step further; it has a special kind of
variable, known as an "I/O path", that is used to identify a device.  The
device address is "assigned" to an I/O path with (logically enough) an ASSIGN
statement as follows:

   ASSIGN @Dev TO 723

Note that "@Dev" is an arbitrary name (though it is one that will be used in
all examples in this document); any other legal variable name can be used, it
just has to start with an "@".  We then can perform our OUTPUT as:

   OUTPUT @Dev;"BEEP"

* But why does RMB bother with I/O paths?  Why not just use an ordinary
variable?

I/O paths do allow marginally faster access to an interface for an I/O
statement (or so I'm told); but the real reason for I/O paths is that you can
perform an ASSIGN with additional parameters to tell RMB how an I/O transaction
is to be performed.  Suppose you output a real array in RMB:

   REAL A(1:512)
   ...
   OUTPUT @Dev;A(*)

The RMB OUTPUT statement will output the entire array to the remote device, but
this doesn't tell you what format the output takes.  Is it in ASCII format,
outputting each number as a string of ASCII digits, separated by commas?  Or is
it a binary format, outputting each number in the array as 8 bytes of binary
data?

                             Converting RMB Programs                          5


Well, if you simply perform an ASSIGN without any parameters, the array is
output in ASCII format; that's logical, because ASCII data is much more
universally understood by computing machines than binary data, and so most
instruments understand ASCII.  But in some specific cases you may need to
output the data as binary; and you can do this simply by adding the FORMAT OFF
parameter to the ASSIGN statement:

   ASSIGN @Dev TO 723;FORMAT OFF

If this is done, the array will be output in binary, not ASCII.  There are
several other optional parameters to ASSIGN but they are rarely used and will
not be discussed further here.

* The point of this long discussion on ASSIGN is that the 82335 has nothing
like it.  The closest thing to:

   ASSIGN @Dev TO 723

-- in the 82335 is:

   Dev& = 723

As long as the ASSIGN has no optional parameters, these two invocations are
equivalent.  However, unlike RMB, simply loading an address into a variable
does nothing to affect how data is output over the HPIB; and so the 82335 uses
different calls to output arrays in ASCII or in binary; to output an array in
ASCII format you use the IOOUTPUTA (output real array) call:

   DIM A!(511)
   NumItems% = 512
   CALL IOOUTPUTA(Dev&, SEG A!(0), NumItems%)

Note that the array is this case is of 32-bit REALs, not 64-bit REALs as in
RMB; IOOUTPUTA can only handle 32-bit REALs.  I point this out to illustrate
another peculiarity of the 82335 relative to RMB:  the 82335 calls are often
much pickier than the comparable RMB statements in terms of the data types
they will handle.

To output an array in binary format you use the IOOUTPUTB (output binary) call:

   DIM A!(511)
   Swap% = 4
   NumItems% = 512 * Swap%
   CALL IOOUTPUTB(Dev&, SEG A!(0), NumItems%, Swap%)

                             Converting RMB Programs                          6


IOOUTPUTB is a little different from most 82335 calls in that it can output data
of any type (a 32-bit real array in this case), since all it does is output a
sequence of raw bytes; note that the length count, "NumItems%", is in bytes,
not array elements.  What the "Swap%" parameter means will be discussed in the
next section.

[%%]


* [3.0] RMB OUTPUT STATEMENT:  To review the previous section, after
ASSIGNing an I/O path to an HPIB interface under RMB, you can output a command
or data to a device with the OUTPUT statement:

   ASSIGN @Dev TO 723
   OUTPUT @Dev;Cmd$                       ! Output a string.
   OUTPUT @Dev;Real_var                   ! Output a variable.
   OUTPUT @Dev;A(*)                       ! Output an array.

These statements have direct equivalents in the 82335 calls:

   Dev& = 723
   CALL IOOUTPUTS(Dev&, Cmd$, LEN(Cmd$))  ' Output a string.
   CALL IOOUTPUT(Dev&, RealVar!)          ' Output a real variable.
   CALL IOOUTPUTA(Dev&, SEG A!(0), 512)   ' Output a real array.

This simple example shows another difference, a big one, between RMB and the
82335.  In the previous section we discussed how different 82335 output calls
are used to output arrays as either ASCII or binary; and that reflects a
general principle.  An RMB OUTPUT statement can output any kind of data; under
the 82335 you have a set of different output calls to output different kinds of
data in different formats.

In most cases, as above, an RMB program will use the OUTPUT statement to send
strings and real numbers as ASCII, so this is nowhere near as big a restriction
as it sounds -- though you do have to pay much more attention to data types
using the 82335 calls than you do with RMB.  For example, you can't use
IOOUTPUT to send an integer, so if you need to output an integer you must
convert it to a real first.

* And so in general, OUTPUT statements that output the contents of a single
variable or array are easily duplicated with the appropriate 82335 output
calls.  However, RMB is capable of outputting as many variables as you like
with a single OUTPUT statement; for a simple example:

   OUTPUT @Dev;"INIT: ";Init_val

Since the 82335 output calls can only output the contents of a single variable
or array, rewriting an RMB statement like this requires some work.

                             Converting RMB Programs                          7


In this simple case, the easiest way to duplicate the actions of the statement
is convert the RMB OUTPUT parameters to a string and then use IOOUTPUTS to
output the resulting string:

   Cmd$="INIT:" + STR$(InitVal)
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

Note that QuickBASIC uses the "+" sign as a string concatenation operator, and
uses the "STR$" function to convert between a numeric value and its string
representation.  By way of comparison, this is equivalent to the RMB
statements:

   Cmd$ = "INIT:" & VAL$(Init_val)
   OUTPUT @Dev;Cmd$

* Unfortunately, this approach becomes impractical for more complicated RMB
OUTPUT statements, for example:

   OUTPUT @Dev;"PARMS:";A(*);":TERM"

-- since a large array many not fit into a string.  The only sensible way to 
do this is use three 82335 output calls -- an IOOUTPUTS, an IOOUTPUTA, and an
IOOUTPUTS again -- to send the three separate parameters.

Now the brute-force approach to doing this would be to just execute all three
calls consecutively as follows:

   Dev&=723
    
   Cmd$="PARMS:"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

   NumItems% = 512
   CALL IOOUTPUTA(Dev&, SEG A!(0), NumItems%)

   Cmd$=":TERM"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

But the brute-force approach is also the dumb one; this will not work, for
two reasons.

                             Converting RMB Programs                          8


* The first reason is that the original RMB OUTPUT statement:

   OUTPUT @Dev;"PARMS:";Array(*);":TERM"

-- outputs all three parameters in sequence and THEN sends a carriage-return
line-feed (CR-LF) terminator sequence:

   PARMS:2342,6787,110,33, ... ,2199:TERM<CR-LF>

In the case of the three 82335 output calls shown above, EACH of the three is
terminated by a CR-LF; which means that the device receives the following
sequence:

   PARMS:<CR-LF>
   2342,6787,110,33, ... ,2199<CR-LF>
   :TERM<CR-LF>

Since the CR-LF terminator tells the device that the command is completed, the
device swallows the "PARMS:" string and, on getting the following CR-LF, thinks
the array values are missing -- and so generates an error indication.

* Second, and much more devious, if you output the commands using the device
address "Dev&" with each of the three 82335 output calls, the 82335
"readdresses" the device with each call.

HPIB is based on a bus-master scheme of control.  To send commands or data to a
device, the controller sends control bytes to set up the transaction.  In this
example, each time the controller executes an 82335 output call, it sends the
control bytes again -- and when the device gets the control bytes, it assumes
that it's supposed to get a new command and that the one you were trying to
send is incomplete ... and, again, you get an error indication.

* Actually, there are easy solutions to both these problems.  The solution to
the first problem is just to use the 82335 IOEOL command to disable sending a
CR-LF for the first two 82335 output calls, and then re-enable a CR-LF for the
last IOUTPUTS call.

The solution to the second problem is a little subtler.  All the 82335 output
calls can use either a device address:

   Dev&=723
   Cmd$=":TERM"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

                             Converting RMB Programs                          9


-- or an ISC:

   Isc&=7
   Cmd$=":TERM"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Isc&, Cmd$, Cmdlength%)

-- to designate the destination for the output.  What's the difference?  In
the case of using a device address, the output call will always send the 
configuration bytes; in the case of using the ISC, the output call has no
information telling it where to send the commands or data, and so simply 
assumes that the remote device has been configured correctly and blasts the
commands or data out the HPIB port.

So to ensure that you only set up the remote device once, you simply have the
first output call in the sequence use the device address, and have the rest use
the ISC.  Adding these two fixes gives us code that works correctly:

   Dev&=723
   Isc&=7
    
   ' First output call, disable EOL, use device address.

   Eol$=""
   CALL IOEOL(Isc&, Eol$, 0)

   Cmd$="PARMS:"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

   ' Second output call, use ISC.

   NumItems% = 512
   CALL IOOUTPUTA(Isc&, SEG A!(0), NumItems%)

   ' Third output call, re-enable EOL to CR-LF, use ISC.

   Eol$=CHR$(13) + CHR$(10)
   CALL IOEOL(Isc&, Eol$, 2)

   Cmd$=":TERM"
   Cmdlength%=LEN(Cmd$)
   CALL IOOUTPUTS(Isc&, Cmd$, Cmdlength%)

* That's one of the nastier problems you can encounter when you try to convert
an RMB program to the 82335, but there are others.

                             Converting RMB Programs                         10


For instance, the HPIB spec defines a control line named EOI (End Or Identify)
which can be asserted at the end of an output to tell the receiving device
that the output is complete.  Normally, this is redundant, since in most cases
an output is terminated by a CR-LF, but most devices don't mind if an EOI is
asserted as well.

Unfortunately, some brain-damaged ones do.  This can lead to confusing
troubles, since by default an RMB OUTPUT statement does not assert EOI; you
have to use an END keyword to specifically tell it to assert the line:

   OUTPUT @Dev;"BEEP",END

The 82335, in contrast, by default always asserts EOI; so if you are having
troubles you might consider using the IOEOI call to turn that off:

   Flag% = 0
   CALL IOEOI (Isc&, Flag%)

* Another problem that arises occurs in output of binary data through the
IOOUTPUTB call.  Traditional RMB systems use Motorola processor chips, and
so do most HP instruments; QuickBASIC with the 82335 runs on a PC that uses
an Intel processor chip.  The signficance of this difference is that the
byte-order of multibyte data elements is reversed on the two types of
processors:  Motorola processors are "big-ender" machines (the most-significant
byte comes first) while Intel processors are "little-ender" machines (the
least-significant byte comes first).

This means that if you use IOOUTPUTB to send 16-bit integer data to an 
instrument, the two bytes for each integer will be reversed -- unless you set
the "Swap%" parameter, mentioned earlier, to a value of 2.  This tells the
IOOUTPUTB call to reverse bytes by pairs.  If you are using IOUTPUTB call to
send 64-bit floating-point numbers, you need to set "Swap%" to 8, so that the
IOOUTPUTB call will reverse bytes in groups of 8.

Note that byte-swapping only applies to binary data output; it is meaningless
for ASCII output, since the order of ASCII is the same on any device.

* One major problem that is too big to address in detail here is the use of
formatted output data.  RMB includes a large set of format codes that specify
data output formats and termination conditions; translating RMB OUTPUT
statements that use format codes to QuickBASIC + 82335 code requires a detailed
knowledge of both languages.

The proper approach is to use QuickBASIC string-handling functions to build up
a string in the proper format, and then use the IOOUTPUTS call to output that
string -- there is an appendix to this document that provides an outline of
QuickBASIC and C string functions.  You may also need to use IOEOL and IOEOI
calls to adjust output termination conditions.

                             Converting RMB Programs                         11


* Finally, though 82335 output calls are clumsier to use than RMB OUTPUT
statements, the 82335 does have a trick or two up its sleeve.  

For example, many modern instruments use the so-called 488.2 arbitrary-block
data-transfer protocol.  Under RMB you have to design an OUTPUT statement to
build up the protocol; it's not hard to do, but the 82335 does bypass this
bother by providing an output call, IOOUTPUTAB, to do it conveniently.

Similarly, under RMB if you wish to output data from a file to a remote device,
your program has to read data in from the file and then output that data.  The
82335 has a call, IOOUTPUTF, that allows you to output the file directly to the
remote device.  These two 82335 output calls can be used to optimize a program
converted from RMB.

[%%]


* [4.0] RMB ENTER STATEMENT:  The discussion concerning the RMB OUTPUT
statement applies in many ways to the RMB ENTER statement, if in reverse.  For
example, simple RMB ENTER statements:

   ASSIGN @Dev TO 723
   ENTER @Dev;Cmd$                               ! Enter a string.
   ENTER @Dev;Real_var                           ! Enter a variable.
   ENTER @Dev;A(*)                               ! Enter an array.

-- have direct equivalents in the 82335 and QuickBASIC:

   Dev& = 723

   Cmd$=SPACE$(32)
   Max%=32
   Actual%=0
   CALL IOENTERS(Dev&, Cmd$, Max%, Actual%)      ' Enter a string.
   CALL IOENTER(Dev&, RealVar!)                  ' Enter a real variable.
   Max%=512
   Actual%=0
   CALL IOENTERA(Dev&, SEG A!(0), 512)         ' Enter a real array.

As with the 82335 output calls, the 82335 enter calls are specific to certain
data types (with the exception of the IOENTERB call), and you have to be
more careful about data types.

                             Converting RMB Programs                         12


Converting RMB ENTER statements that enter into multiple variables is as
tricky using 82335 enter calls as is converting RMB OUTPUT statements to
82335 output calls.  In simple cases, you can use an IOENTERS to read all the
variables into a string, and then use QuickBASIC string functions to tear
out the fields you want.

But if you want to enter some complicated system of variables, you have to
use multiple 82335 enter calls, and this gets as tricky for enters as it is
for outputs. 

The problem with HPIB configuration commands disrupting the sequence is the
same with enters as for outputs, and it has the same solution:  use the device
address on the first 82335 enter call, then use the ISC on all following calls
in the sequence.

The problems with EOL sequences that make the use of multiple 82335 output
calls difficult are replaced by a different concern with 82335 input calls:
the need for some action to terminate the enter.  For example, in the case of
the IOENTERS (enter string) call, the string entry can be terminated by any
or all of three conditions:

 % Receiving a termination character (LF by default).
 % Receiving an EOI.
 % Receiving the specified number of characters.

If you are using an 82335 enter call to input a string that is part of a longer
sequence, the first two items cannot occur until the end of the longer
sequence, so the third item is the that will end entry into the string.

For example, let's consider writing some QuickBASIC + 82335 code to enter the
command string we used in the previous section of this document:

   PARMS:2342,6787,110,33, ... ,2199:TERM<CR-LF>

You could do this as follows:

   Dev&=723
   Isc&=7

   ' Enter header (first five characters) from device.

   Cmd$=SPACE$(5)
   Max%=5
   Actual%=0
   CALL IOENTERS(Dev&, Cmd$, Max%, Actual%)

   ' Enter data from interface.

   Max%=512
   Actual%=0
   CALL IOENTERA(Isc&, SEG A!(0), 512)

                             Converting RMB Programs                         13


   ' Enter trailer (CR-LF terminated) from interface.

   Cmd$=SPACE$(32)
   Max%=32
   Actual%=0
   CALL IOENTERS(Isc&, Cmd$, Max%, Actual%)

There's no need to get the exact number of characters on the final IOENTERS,
because the string is terminated by a CR-LF, so we make the "Max%" count to
be a nice, relatively large number of characters.

* There's an additional item of interest when performing 82335 enter calls.
When a device returns multiple items of information at a time, in most cases it
will separate the items by commas and end the information with a CR-LF.

The most brute-force approach to dealing with this is, as suggested previously,
read the entire set into a string and then tear the items out.  However, you
may be able to do this in a more convenient fashion using the 82335 IOMATCH
call, which allows you to set the input-termination ("match") character.  When
you want to enter the individual items in the set, you can make the match
character a comma:

   Match$=","
   Flag%=1
   CALL IOMATCH(Isc&, Match$, Flag%)

-- enter each of the items in the set (using the device address for the first
and the ISC for the rest), and reset the match character to a line-feed before
entering the last item:

   Match$=CHR$(10)
   Flag%=1
   CALL IOMATCH(Isc&, Match$, Flag%)

* As for the other concerns raised in the last section:

 % EOI is not an important concern with 82335 enter calls.  If an EOI
   occurs, the enter will be terminated, but since an EOI is never (in any
   rational device) used for anything but that purpose, that makes no
   difference in practice.

 % When you are entering binary data using the 82335 IOENTERB (enter binary)
   call, you obviously need to still be concerned about byte-swapping.  Another
   consideration for IOENTERB is that you must use IOMATCH to disable the
   match character; otherwise your binary input could be prematurely terminated
   by a byte that has the same code as the match character.

                             Converting RMB Programs                         14


 % The 82335 enter calls include equivalents to the IOOUTPUTAB and IOUTPUTF
   calls that perform the same operations in the reverse direction: IOENTERAB
   enters arbitrary-block data, and IOENTERF enters data directly into a file
   -- and can be used to simplify actions that are complicated in an RMB
   program.

[%%]


* [5.0] ERROR, TIMEOUT, & SRQ HANDLING:  In RMB, error handling (at
least in its simplest form) is performed by setting an EVENT to trap the
errors:

   ON ERROR GOTO Errtrap
   OUTPUT @Dev;"THIS IS A TEST"

The error handler code can then use ERRN (or other error functions) to
determine the nature of the error.  On the 82335, this is a somewhat more
laborious process; each call returns an error code that you have to then check
for directly:

   CALL IOOUTPUTS(Dev&, CMD$, LEN(CMD$))
   IF PCIB.ERR <> NOERR THEN GOTO Errtrap

Note that this IF statement causes a jump to user-defined error-handler code;
if you don't want to bother with that, you can use the default error handler
configured by the 82335 software:

   CALL IOOUTPUTS(Dev&, CMD$, LEN(CMD$))
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

Note that none of the examples in this document before this one incorporate
error handling.  It was deleted for the sake of simplicity; in practice you
should always incorporate error handling into your QuickBASIC + 82335 programs.

* The differences between RMB and 82335 timeout handling are closely related to
the differences between the two for error handling.  In RMB, timeouts are
handled by trapping an EVENT much as errors are trapped:

   ON TIMEOUT 7,10 GOTO Timeout
   OUTPUT @Dev;"THIS IS A TEST"

This specifies a 10-second timeout on the interface with select code 7.  Under
the 82335, you use the IOTIMEOUT call to set up the timeout interval:

   CALL IOTIMEOUT(Isc&, 10)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

                             Converting RMB Programs                         15


After that, a timeout can occur on 82335 I/O calls; the timeout is returned as
an error code, just like any other error code:

   CALL IOOUTPUTS(Dev&, CMD$, LEN(CMD$))
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

* RMB has commands that allow it to trap a device HPIB SRQ (among many other
interface conditions) and branch to a handler routine.  This capability is
provided by the ON INTR statment:

   ON INTR 7 GOSUB Hpib_trap

This specifies where an interrupt on an interface at ISC 7 will go; you have
to specify the interface condition itself with the ENABLE INTR statement:

   ENABLE INTR 7,2

This specifies an interrupt on SRQ.  To disable the trap you perform:

   OFF INTR 7

The 82335 has a much simpler capability to perform a trap when a device SRQ is
asserted, through the IOPEN command:  

  CALL IOPEN(Isc&, 1)

This takes over the QuickBASIC ON PEN jump, so you can then set a jump to an
SRQ interrupt handler with:

  ON PEN GOSUB HpibTrap

You can then disable the trap with:

   CALL IOPEN(Isc&, 0)

However, this only works under QuickBASIC, QBASIC, or Professional BASIC; it
will not work under C or Pascal.  You can as an alternative simply use IOSTATUS
to poll to see if SRQ is asserted, as follows:

   SrqLine%=1
   DO
      CALL IOSTATUS(Isc&, SrqLine%, LineSet%)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   LOOP UNTIL LineSet% = 1

This will work (modified to the proper syntax) in all supported languages.

[%%]

                             Converting RMB Programs                         16


* [6.0] OTHER I/O STATEMENTS:  There are various other RMB I/O
statements that you will encounter and that have one-to-one equivalents in
the 82335; the following table lists these statements:

 +---------------+------------+--------------------------------------------+
 | RMB           | 82335      | function                                   |
 +===============+============+============================================+
 | RESET         | IORESET    | Put interface in power-up state.           |
 | CLEAR         | IOCLEAR    | Restore interface to defaults.             |
 | ABORT         | IOABORT    | Stop HPIB transaction.                     |
 | LOCAL         | IOLOCAL    | Put remote device into local operation.    |
 | LOCAL LOCKOUT | IOLLOCKOUT | Lock out remote device front panel.        |
 | REMOTE        | IOREMOTE   | Set remote device take commands from HPIB. |
 | SPOLL         | IOSPOLL    | Serial-poll device.                        |
 | TRIGGER       | IOTRIGGER  | Trigger devices.                           |
 +---------------+------------+--------------------------------------------+

It is also common to see STATUS and CONTROL statements in an RMB program that
does HPIB I/O; while it is true that the 82335 does include similar IOSTATUS
and IOCONTROL calls, there's no neat mapping between the status and control
provided by the RMB statements and that provided by the 82335 calls (though
there are similarities in some cases as both RMB and the 82335 use the same TI
9914 HPIB chip).

* RMB has a statement, named SEND, that allows a program to execute low-level
HPIB configuration commands; for example, the following SEND sequence tells
a device at address 7 to accept a command string:

   SEND 7;UNL UNT MTA LISTEN 7 DATA "BEEP"

Each of the SEND keywords specifies a low-level HPIB command, except for the
DATA keywoard, which ends the command sequence (in HPIB terminology, releases
the ATN line) and sends device commands or data.  SEND is used for unusual
HPIB configuration problems and its use requires some level of expertise.

The 82335 uses a similar IOSEND call, but it is a little bit more difficult to
deal with; you have to know the actual byte codes for the low-level HPIB
commands, and you can't send device commands or data with it.  If you want to
send device commands or data you have to follow the IOSEND with an IOCONTROL
call to release ATN, and then use an IOUTPUTS to the ISC to output the string:

   Isc& = 7 

   Unl$   = CHR$(63)            ' UNLISTEN HPIB command.
   Unt$   = CHR$(95)            ' UNTALK HPIB command.
   Taddr$ = CHR$(64 + 30)       ' Controller talk address.
   Laddr$ = CHR$(32 + 7)        ' Device listen address.

                             Converting RMB Programs                         17


   Cmd$ = Unl$ + Unt$ + Taddr$ + Laddr$
   Length% = LEN(CMD$)
   CALL IOSEND(Isc&, Cmd$, Length%)             ' Send HPIB commands.
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   Cond% = 8            
   Stat% = 0
   CALL IOCONTROL(Isc&, Cond%, Stat%)           ' Release ATN.
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   Cmd$ = "BEEP"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Isc&, Cmd$, Length%)          ' Send data.
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

* Finally, RMB has statements to perform parallel polls and pass control;
the 82335 has calls that perform similar functions, but these functions are
little used, and will not be discussed further here.

[%%]


* [7.0] A FEW QUICKBASIC EXAMPLES:  With the fundamentals explained,
let's demonstrate converting a few RMB programs to QuickBASIC + 82335.  For our
first example, let's consider a simple program to communicate with a typical HP
instrument:

   ________________________________________________________________________

   10   ASSIGN @Dev TO 717
   20   REMOTE @Dev
   30   OUTPUT @Dev;"*RST"
   40   OUTPUT @Dev;"TRIG2"
   50   OUTPUT @Dev;"*SRE1"
   60   OUTPUT @Dev;"DFMT1"
   70   OUTPUT @Dev;"DBIN1"
   80   OUTPUT @Dev;"COMP1"
   90   ON INTR 7 GOTO Meas_end
   100  FOR I=1 TO 100
   110     ENABLE INTR 7;2 !           Set SRQ interrupt.
   120     OUTPUT @Dev;"*TRG"
   130  Waiting: GOTO Waiting
   140  Meas_end: DISABLE INTR 7
   150     S=SPOLL(@Dev)
   160     OUTPUT @Dev;"DATA?"
   170     ENTER @Dev;C,D,B
   180     PRINT C,D,B
   190  NEXT I
   200  END
   ________________________________________________________________________

                             Converting RMB Programs                         18


This program can be readily converted to QuickBASIC + 82335 with relatively few
changes.  Let's take a quick trip through this program to get our bearings:

 % 10 ASSIGN @Dev TO 717

   This RMB statement sets up an I/O path to the instrument at address 717.  The
   analogous operation under QuickBASIC would, of course, be:

      Dev& = 717

 % 20 REMOTE @Dev

   This RMB statement puts the instrument into remote mode; we use the
   comparable 82335 IOREMOTE call:

      CALL IOREMOTE(Dev&)

 % 30 OUTPUT @Dev;"*RST"

   This RMB statement sends a string to the instrument; the 82335 IOOUTPUTS
   call is the logical equivalent:

      Cmd$="*RST"
      Cmdlength%=LEN(Cmd$)
      CALL IOOUTPUTS(Dev&, Cmd$, Cmdlength%)

   All the other RMB string OUTPUT statements map to similar IOUTPUTS calls.

 % 90   ON INTR 7 GOTO Meas_end
   ...
   110     ENABLE INTR 7;2

   These RMB statements set up an interrupt jump when the instrument asserts
   the SRQ line over the HPIB cable.  We could use the 82335 IOPEN call and the
   QuickBASIC ON PEN statement to do the same thing, but since the program
   isn't really doing anything while it waits for an SRQ, it's much easier
   to use IOSTATUS to repeatedly check to see if the SRQ line is set:

      Isc&=7
      SrqLine%=1
      DO
         CALL IOSTATUS (Isc&, SrqLine%, LineSet%) '  Check for SRQ set.
      LOOP UNTIL LineSet%=1

                             Converting RMB Programs                         19


 % 150 S=SPOLL(@Dev)

   This RMB statement asserts a serial poll of the instrument to see if it
   asserted the SRQ, and to clear the SRQ; the instrument returns a status byte.
   In this case, the only reason the program does that is to tell the
   instrument to clear the SRQ line, but in other cases -- multiple instruments
   on the HPIB, for example -- it may have to poll multiple instruments to
   determine which asserted the SRQ.  (The instrument that asserts the SRQ will
   have bit 6 of its status byte set.)

   The 82335 does this easily with the IOSPOLL call:

      CALL IOSPOLL(Dev&,StatusByte%)

 % 170 ENTER @Dev;C,D,B

   This RMB ENTER statement pulls data -- three REAL numbers -- back in from the
   instrument.  An 82335 IOENTER call can read in a numeric variable, but each
   call can only read one value; so you can instead use IOENTERA to enter the
   three values into an array as follows:

      DIM DataArray!(3)
      Max%=3
      Actual%=0
      CALL IOENTERA(Dev&, SEG DataArray!(0), Max%, Actual%)

The following complete program puts these items together:

   ____________________________________________________________________

   ' QuickBASIC HPIB Example Program 1
   
   REM $INCLUDE: 'QBSETUP'

   CLS
   DIM DataArray!(3)

   Dev&     = 717
   Isc&     = 7
   SrqLine% = 1

   PRINT "Reset everything!"

                             Converting RMB Programs                         20


   CALL IORESET(Isc&)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   CALL IOREMOTE(Dev&)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   CALL IOTIMEOUT(Isc&, 5!)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   PRINT "Send commands!"
   
   Cmd$ = "*RST"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Isc&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   Cmd$ = "TRIG2"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   Cmd$ = "*SRE1"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   Cmd$ = "DFMT1"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   Cmd$ = "DBIN1"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   Cmd$ = "COMP1"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   PRINT "Get Data!"
   
   FOR I% = 1 TO 100
     
      Cmd$ = "COMP1"
      Length% = LEN(Cmd$)
      CALL IOOUTPUTS(Dev&, Cmd$, Length%)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

                             Converting RMB Programs                         21


   '   Loop until SRQ asserted.

      DO
         CALL IOSTATUS(Isc&, SrqLine%, LineSet%)
         IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      LOOP UNTIL LineSet% = 1

   '   Use SPOLL to clear SRQ.

      CALL IOSPOLL(Dev&, StatusByte%)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
   '   Get data items back from device.

      Max% = 3
      Actual% = 0
      CALL IOENTERA(Dev&, SEG DataArray!(0), Max%, Actual%)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   
      PRINT DataArray!(0), DataArray!(1), DataArray(2)
   
   NEXT I%

   END
   ____________________________________________________________________

* Our second example program is similar, if a bit simpler.  Note that some of
the OUTPUT statements have been deleted for the sake of brevity.

   _______________________________________________________________________

   10   ASSIGN @Dev TO 717
   20   REMOTE @Dev
   30   OUTPUT @Dev;"*RST;*CLS"
   ...
   70   OUTPUT @Dev;"INIT:CONT ON"
   80   FOR I=0 TO 9
   90      TRIGGER @Dev
   100     ENTER @Dev;A,B,C,D
   110     PRINT A,B,C,D
   120  NEXT I
   130  END
   _______________________________________________________________________

                             Converting RMB Programs                         22


This RMB program translates to the following QuickBASIC + 82335 program:

   _______________________________________________________________________

   ' QuickBASIC HPIB Example Program 2.
   
   REM $INCLUDE: 'QBSETUP'
   
   Dev& = 717
   Isc& = 7
   Flag% = 0
   CALL IOEOI (Isc&, Flag%)'    Disable EOI.

   Cmd$ = "*RST;*CLS"
   Length% = LENGTH(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   ... 
   Cmd$ = "INIT:CONT ON"
   Length% = LENGTH(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   FOR I%=0 TO 9
      CALL IOTRIGGER (Dev&)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

      CALL IOMATCH(Isc&, ',' 1)
      CALL IOENTER(Dev&,A)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      CALL IOENTER(Isc&,B)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      CALL IOENTER(Isc&,C)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      CALL IOMATCH(Isc&, CHR$(10), 1)
      CALL IOENTER(Isc&,D)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

      PRINT A,B,C,D
   NEXT I%
   END
   _______________________________________________________________________

This is a pretty straightforward mapping, with a few comments:

 % This program turns off the EOI line as one of the first things it does.
   As noted, RMB never asserts EOI on an OUTPUT statement unless you
   specifically tell it to; the 82335 always asserts EOI unless you
   specifically tell it not to.  This particular instrument doesn't like
   EOI, so I turn it off.

                             Converting RMB Programs                         23


 % The RMB program uses a single ENTER statement to grab the four numbers 
   returned from the instrument:  
   
      ENTER @Dev;A,B,C,D
   
   Also as noted earlier, the IOENTER call can only handle a single parameter.
   This means that to enter four such variables, you can use an IOENTER to
   enter them into a four-element array, as was done in example program 1; or
   you can use four IOENTER calls, as this program does:

      CALL IOMATCH(Isc&, ',' 1)
      CALL IOENTER(Dev&,A)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      CALL IOENTER(Isc&,B)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      CALL IOENTER(Isc&,C)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
      CALL IOMATCH(Isc&, CHR$(10), 1)
      CALL IOENTER(Isc&,D)
      IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   Note the trick used, however; the first IOENTER call uses the device address
   ("Dev&") as the destination; the others use the card select code ("Isc&").
   Note also how the match character is changed to allow proper entry of the
   numbers.

* One unusual thing that is occasionally done with HPIB instruments is to dump
screen displays directly to a plotter or printer on the same HPIB.  This is
tricky because the controlling computer has to tell the instrument to do the
dump, and then set up the instrument to talk and the plotter or printer to
listen.

In RMB, this requires use of the SEND statement; for example, to have a
spectrum analyzer dump its display directly to a plotter over HPIB, you would
execute the following RMB statements:

   _______________________________________________________________________

   OUTPUT 718;DATA "SNGLS"
   OUTPUT 718;DATA "PLOT 0,0,10365,7962"
   SEND 7;UNL UNT LISTEN 5 TALK 18 DATA
   _______________________________________________________________________

The last statement is the important one:  it tells the plotter to listen and
the analyzer to talk; the DATA keyword at the end releases the HPIB ATN line
-- and then the analyzer dumps to the plotter.

This assumes a spectrum analyzer at address 718 and a plotter at address 705;
note that the instrument commands used here are specific to a particular
spectrum analyzer and won't necessarily apply to other instruments (though the
commands tend to be somewhat similar from instrument to instrument).

                             Converting RMB Programs                         24


You can do the same things with the 82335, but you have to be a little
cleverer, as the following code fragment shows:

   _______________________________________________________________________

   Dev& = 718                    ' Analyzer address.
   Isc& = 7                      ' Interface select code.

   Plt& = 705                    ' Plotter address.  

   Taddr$ = CHR$(64 + 18)        ' Analyzer talk address.
   Laddr$ = CHR$(32 + 5)         ' Plotter listen address.
   Unl$   = CHR$(63)             ' UNLISTEN HPIB command.
   Unt$   = CHR$(95)             ' UNTALK HPIB command.

   ' Tell analyzer to take a sweep.

   Cmd$ = "PRINT;"              
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   ' Tell analyzer to dump plot.

   Cmd$ = "DATA "PLOT 0,0,10365,7962"
   Length% = LEN(Cmd$)
   CALL IOOUTPUTS(Dev&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   ' Tell analyzer to talk and plotter to listen:

   Cmd$ = Unl$ + Unt$ + Laddr$ + Taddr$
   Length% = LEN(CMD$)
   CALL IOSEND(Isc&, Cmd$, Length%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR

   ' VERY IMPORTANT -- release ATN!

   Cond% = 8            
   Stat% = 0
   CALL IOCONTROL(Isc&, Cond%, Stat%)
   IF PCIB.ERR <> NOERR THEN ERROR PCIB.BASERR
   _______________________________________________________________________

[%%]
   
                             Converting RMB Programs                         25


* [APPENDIX] STRING HANDLING:  As implied earlier in this document, the
lack of much in the way of formatted-I/O functions in the 82335 means that you
often have to enter data as a single long string and then use the target
language's string functions to decipher it.  However, no DOS or Windows
language uses exactly the same string functions as RMB, so this may be a
troublesome operation.

* For the most fundamental example, string concatenation is performed under RMB
with the "&" character:

   Cmd$ = "LEVEL:" & VAL$(My_var)

In QuickBASIC, as you should have noticed by now, you use the "+" character for
string concatenation:

   Cmd$ = "LEVEL:" + STR$(My_var)

As these two contrasting examples show, the RMB VAL$ statement (which converts
a numeric variable into a string representation) translates into the equivalent
QuickBASIC STR$ statement.  In general, string functions in RMB and QuickBASIC
have this kind of equivalence:  they have functions that operate in an almost
identical fashion but have, for the most part, different names, as the table
below shows:

   +-------------+--------------------+-----------------------------------+
   | RMB         | QB                 | function                          | 
   +=============+====================+===================================+
   | CHR$(N)     | CHR$(N%)           | convert ASCII code into character | 
   | IVAL$(N,8)  | OCT$(N%)           | convert number to octal string    | 
   | IVAL$(N,16) | HEX$(N%)           | convert number to hex string      | 
   | LEN(S$)     | LEN(S$)            | get length of string              |
   | LWC$(U$)    | LCASE$(U$)         | convert string to lower case      |
   | NUM(C$)     | ASC(C$)            | convert character to ASCII code   |
   | POS(S$,S$)  | INSTR(T$,S$)       | get position of substring         |
   | RPT$(S$,N)  | STRING$(N,S$)      | repeat string                     |
   | TRIM$(S$)   | LTRIM$(RTRIM$(S$)) | trim leading and trailing spaces  |
   | UPC$(L$)    | UCASE$(L$)         | convert string to upper case      |
   | VAL(S$)     | VAL(S$)            | convert numeric string to value   |
   | VAL$(N)     | STR$(N%)           | convert value to numeric string   |
   +-------------+--------------------+-----------------------------------+

                             Converting RMB Programs                         26


Note that QuickBASIC also has a string function similar to RPT$ that only
repeats string characters:

   PRINT SPACE$(80)

-- prints 80 spaces.  Beware that it is an easy mistake to enter this as
"SPACES$", but the form is singular, not plural:  "SPACE$".

* One major way in which RMB and QuickBASIC string handling differs is in
dealing with substrings.  In RMB, you can access substrings using subscripts;
for example:

   PRINT S$[3,6]

-- prints the substring of S$ starting at character 3 and ending at character
6; while:

   PRINT S$[3;6]

-- prints the 6 characters following character 3.  

In QuickBASIC, you have to use a function, MID$, to get a substring:

   PRINT MID$(S$, 3, 6)

-- prints the 6 characters following character 3.  A variation on this syntax
is also used to replace substrings; for example:

   MID$(S$, 6, 1) = Ch$

-- replaces character 6 of S$ with the character in Ch$.  QuickBASIC also has
two other functions related to MID$, one to access substrings from the start of
the string:

   PRINT LEFT$(S$, N%)

-- and one to access substrings from the end of the string:

   PRINT RIGHT$(S$, N%)

This last is actually somewhat handy, since in RMB you would have to do this
operation as follows:

   PRINT S$[LEN(S$)-N;N]

* If translating string functions to QuickBASIC is troublesome, translating
them to C is a real pain.  Under C, a string is simply an array of bytes,
terminated by a NULL (code 0) character; you can define your own functions to
perform string operations, or you can use the standard C string-function
libraries.  In either case, the syntax of the operations resembles those of the
comparable RMB operations in no obvious way.  

                             Converting RMB Programs                         27


Some operations that require string functions in RMB require no special
considerations in C.  For example, there is no need in C to have a function
such as CHR$ to generate a character from an ASCII code, or NUM to do the
reverse, since under C you can perform numeric or string operations on a 
character variable as you please:

   unsigned int ch;
   ...
   ch = 35;
   if (ch == 'a') 
   {
   ...

Others that require no special considerations under RMB require library
functions under C.  For example, to perform the RMB operation:

   Cmd$ = "LEVEL:" & VAL$(My_var)

-- under C would be done as:

   strcpy(cmd,strcat("LEVEL:", itoa(myvar));

Useful library functions include:

   +---------+-------------------------------------------------+
   | atoi    | Convert ASCII numeric string to integer number. |
   | itoa    | Convert integer number to ASCII numeric string. |
   | strcat  | Concatenate strings.                            |
   | strcpy  | Copy strings.                                   |
   | strdup  | Duplicate a string.                             |
   | strncat | Append characters to string.                    |
   | strncpy | Copy substring from one string to another.      |
   | strchr  | Find position of character in string.           |
   | strcmp  | Compare two strings.                            |
   | strlen  | Get length in bytes of string.                  |
   | strlwr  | Convert string to lower case.                   |
   | strupr  | Convert string to upper case.                   |
   +---------+-------------------------------------------------+

A full discussion of this (incomplete) list of string functions is way beyond
the scope of this document; this is just a quick conceptual introduction to
allow you to figure out where to proceed in your C language documentation.

                             Converting RMB Programs                         28


* If you need to assemble more complicated commands, you can do this with the C
"sprintf" function, which is very similar to the C "printf" (formatted output)
function -- but generates output into a string.  For example:

   for (n=1;n<=25;++n)
   {
      sprintf (str, "DISP 'MY STRING NR: %d' ", n);
      printf ("%s\n",str);
   }

This is roughly equivalent to the RMB statements:

   FOR N=1 TO 25
      Str$="DISP 'MY STRING NR: "&VAL$(N)&"'"
      PRINT Str$
   NEXT N

There is also a related "scanf" function to allow you to read fields from a 
string into variables.  Again, a full discussion of these commands is beyond
the scope of this document; please consult your C language documentation for
details.

[<>]

org  / gvg / 01 jan 93
v1.1 / gvg / 28 feb 93 / Minor cosmetic changes.
v1.2 / gvg / 03 mar 93 / More minor cosmetic changes for HPIB B.01.00.
